import 'dart:io';
import 'package:path_provider/path_provider.dart';
import 'package:path/path.dart' as p;
import 'log_output.dart';
import 'log_entity.dart';

class FileOutput extends LogOutput implements LogOutputAsync {
  File? _file;
  IOSink? _sink;

  final List<OutputEvent> _eventQueue = [];
  bool _isInitializing = false;
  
  // 日志目录相对路径名，表示在文档目录下的子目录
  final String logDirRelative = 'logs';
  final String logPrefix = 'app';
  final int maxSizeBytes = 5 * 1024 * 1024;

  String _currentDate = '';
  int _currentIndex = 0;
  Future<void> _writeQueue = Future.value();

  // 存储完整的、有权限的目录路径
  String? _logDirFullPath; 

  @override
  Future<void> init() async {
    await _initFile();
    _isInitializing = true;
    for (final event in _eventQueue) {
      await output(event);
    }
    _eventQueue.clear();
  }

  Future<void> _initFile() async {
    try {
      // 获取应用文档目录的完整路径
      final documentsDirectory = await getApplicationDocumentsDirectory();
      
      // 构建 logs 目录的完整绝对路径
      _logDirFullPath = p.join(documentsDirectory.path, logDirRelative);

      // 使用完整的路径来创建 Directory 实例
      final dir = Directory(_logDirFullPath!);
      if (!await dir.exists()) {
        await dir.create(recursive: true); // 递归创建父目录（如果需要）
      }

      _currentDate = _today();
      _currentIndex = await _resolveNextIndex();
      await _openNewSink();

      // 调试：打印实际的日志目录
      print('Log directory created at: $_logDirFullPath');

    } catch (e, stackTrace) {
      print('Failed to initialize file output: $e\n$stackTrace');
    }
  }

  @override
  Future<void> output(OutputEvent event) async {
    // 如果_logDirFullPath为null，说明初始化失败，直接返回
    // if (_logDirFullPath == null) {
    //   // 如果文件输出未初始化成功，则输出到控制台
    //   event.lines.forEach(print);
    //   return;
    // }

    if (!_isInitializing) {
      _eventQueue.add(event);
      return;
    }
    
    _writeQueue = _writeQueue.then((_) async { 
      final today = _today();
      if (today != _currentDate) {
        await _switchToNewDate(today);
      }

      // 确保_sink不为null
      if (_sink == null) {
        await _openNewSink();
      }

      for (final line in event.lines) {
        _sink?.write(line);
      }

      // 确保每次都刷新到文件
      try {
        await _sink?.flush();
      } catch (e) {
        print('Failed to flush log to file: $e');
      }

      // 确保 _file 不为 null 再检查长度
      try {
        if (_file != null && (await _file!.length()) >= maxSizeBytes) {
          await _rotate();
        }
      } catch (e) {
        print('Failed to check file size: $e');
      }
    }).catchError((error) {
      // 如果写入队列出错，至少将日志打印到控制台
      print('Error writing to log file: $error');
      event.lines.forEach(print);
    });
  }

  Future<void> _switchToNewDate(String today) async {
    // 添加对_logDirFullPath的检查
    if (_logDirFullPath == null) return;
    
    try {
      await _sink?.flush();
    } catch (e) {
      print('Failed to flush during date switch: $e');
    }
    await _sink?.close();

    _currentDate = today;
    _currentIndex = await _resolveNextIndex();
    await _openNewSink();
  }

  Future<void> _rotate() async {
    // 添加对_logDirFullPath的检查
    if (_logDirFullPath == null) return;
    
    try {
      await _sink?.flush();
    } catch (e) {
      print('Failed to flush during rotation: $e');
    }
    await _sink?.close();
    _currentIndex++;
    await _openNewSink();
  }

  Future<void> _openNewSink() async {
    // 添加对_logDirFullPath的检查
    if (_logDirFullPath == null) return;
    
    // 使用完整的路径来创建文件
    final fileName = '${logPrefix}_${_currentDate}_$_currentIndex.log';
    _file = File(p.join(_logDirFullPath!, fileName));
    _sink = _file!.openWrite(mode: FileMode.append);
  }

  // 注意：在 _resolveNextIndex 中，也需要使用 _logDirFullPath!
  Future<int> _resolveNextIndex() async {
    // 添加对_logDirFullPath的检查
    if (_logDirFullPath == null) return 1;
    
    final datePrefix = '${logPrefix}_${_currentDate}_';
    // 使用 _logDirFullPath! 而不是 logDir
    final existing = Directory(_logDirFullPath!)
        .listSync()
        .whereType<File>()
        .where((f) => p.basename(f.path).startsWith(datePrefix))
        .toList();

    if (existing.isEmpty) return 1;

    final indices = existing.map((f) {
      final name = p.basename(f.path);
      final parts = name.split('_');
      final indexStr = parts.last.split('.').first;
      return int.tryParse(indexStr) ?? 0;
    }).toList();

    return (indices..sort()).last + 1;
  }

  String _today() {
    final now = DateTime.now();
    return "${now.year.toString().padLeft(4, '0')}-${now.month.toString().padLeft(2, '0')}-${now.day.toString().padLeft(2, '0')}";
  }

  @override
  Future<void> destroy() async {
    try {
      await _sink?.flush();
    } catch (e) {
      print('Failed to flush during destroy: $e');
    }
    await _sink?.close();
  }
}



